package com.google.code.memoriesalbum.controller.oauth;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.datastore.Datastore;

import com.google.appengine.api.datastore.DatastoreTimeoutException;
import com.google.code.memoriesalbum.model.Account;
import com.google.code.memoriesalbum.util.CalendarUtil;
import com.google.code.memoriesalbum.util.Constants;
import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthException;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.util.ServiceException;

/**
 * GoogleのPicasa,Calendarサービスへのアクセスを許可してもらってコールバックされた時のハンドラ。
 * @author shin1ogawa
 */
public class SaveController extends Controller {

	static final Logger logger = Logger.getLogger(SaveController.class.getName());


	@Override
	public Navigation run() {
		if (StringUtils.isEmpty(asString("token"))) {
			logger.log(Level.INFO, "ランダムトークンが設定されていません。");
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			return null;
		}
		if (StringUtils.isEmpty(asString("secret"))) {
			logger.log(Level.INFO, "シークレットキーが設定されていません。");
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			return null;
		}
		try {
			return saveToken();
		} catch (OAuthException e) {
			throw new RuntimeException(e);
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		} catch (ServiceException e) {
			throw new RuntimeException(e);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	private Navigation saveToken() throws OAuthException, MalformedURLException, ServiceException,
			UnsupportedEncodingException {
		//パラメータを設定する
		GoogleOAuthParameters params = new GoogleOAuthParameters();
		params.setOAuthConsumerKey(Constants.CONSUMER_KEY);
		params.setOAuthSignatureMethod("HMAC-SHA1");
		params.setOAuthConsumerSecret(Constants.CONSUMER_SECRET);
		params.setOAuthTokenSecret(asString("secret"));

		//アクセス用トークンを取得する
		GoogleOAuthHelper helper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
		try {
			helper.getAccessToken(request.getQueryString(), params);
		} catch (OAuthException e) {
			logger.log(Level.WARNING, "アクセストークンの取得に失敗しました。", e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			throw e;
		}

		String email =
				CalendarUtil.getUserEmailViaCalendarService(params.getOAuthToken(), params
					.getOAuthTokenSecret());

		//トークンをデータストアに設定する
		Account account = new Account();
		account.setKey(Datastore.createKey(Account.class, asString("token")));
		account.setEmail(email);
		account.setToken(params.getOAuthToken());
		account.setTokenSecret(params.getOAuthTokenSecret());
		for (int i = 0; i < 5; i++) {
			try {
				Datastore.put(account);
				break;
			} catch (DatastoreTimeoutException e) {
				// retry
			}
		}
		logger.info("OAuthTokensを保存しました。:" + ToStringBuilder.reflectionToString(account));
		return null;
	}
}
